﻿using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using OpenWaves.Pagination;

namespace OpenWaves.UnitTests
{
    [TestFixture]
    public class GetRangeExtensionTests
    {
        [Test]
        public void When_collection_is_empty_GetRange_returns_empty_Enumerable()
        {
            var collection = new int[] { };

            Assert.That(collection.GetRange(0, 1), Is.Empty);
        }

        [Test]
        public void When_collection_contains_range_GetRange_returns_the_range()
        {
            var collection = new[] { 0, 1, 2, 3, 4, 5 };

            Assert.That(collection.GetRange(2, 2), Is.EquivalentTo(new[] { 2, 3 }));
        }

        [Test]
        public void When_firstItemIndex_is_greater_then_collection_size_GetRange_returns_empty_Enumerable()
        {
            var collection = new[] { 0, 1, 2, 3, 4, 5 };

            Assert.That(collection.GetRange(10, 2), Is.Empty);
        }

        [Test]
        public void When_maxItemsCount_exceeds_collection_size_GetRange_returns_smaller_range()
        {
            var collection = new[] { 0, 1, 2, 3, 4, 5 };

            Assert.That(collection.GetRange(3, 10), Is.EquivalentTo(new[] { 3, 4, 5 }));
        }

        [Test]
        public void Given_collection_is_ILazyCollection_GetRange_calls_ILazyCollection_GetRange_and_does_not_enumerate_collection()
        {
            var collectionMock = new Mock<ILazyCollection<int>>();
            collectionMock.Setup(c => c.GetRange(5, 10)).Returns(Enumerable.Repeat(0, 10));
            collectionMock.Setup(c => c.GetEnumerator()).Throws(new AssertionException("Attempted to enumerate the collection."));
            var collection = collectionMock.Object as IEnumerable<int>;

            //
            // Call ToList() to force enumeration of the result.
            //
            collection.GetRange(5, 10).ToList();
        }        

        [Test]
        public void Given_collection_is_IQueryable_GetRange_does_not_enumerate_the_collection()
        {
            IQueryable<int> underlyingEnumerable = new EnumerableQuery<int>(new[] { 0, 1, 2 });
                        
            var collectionMock = new Mock<IQueryable<int>>();
            collectionMock.Setup(c => c.Provider).Returns(underlyingEnumerable.Provider);
            collectionMock.Setup(c => c.Expression).Returns(underlyingEnumerable.Expression);
            collectionMock.Setup(c => c.GetEnumerator()).Throws(new AssertionException("Attempted to enumerate the collection."));
            var collection = collectionMock.Object as IEnumerable<int>;

            //
            // Call ToList() to force enumeration of the result.
            //
            collection.GetRange(5, 10).ToList();            
        }
    }
}